fs          = require 'fs'
path        = require 'path'
gulp        = require 'gulp'
apf         = require 'gulp-autoprefixer'
coffee      = require 'gulp-coffee'
concat      = require 'gulp-concat'
connect     = require 'gulp-connect'
clean       = require 'gulp-clean'
html2js     = require 'gulp-html2js'
less        = require 'gulp-less'
marked      = require 'gulp-marked'
minifyCss   = require 'gulp-minify-css'
minifyHtml  = require 'gulp-minify-html'
ngAnnotate  = require 'gulp-ng-annotate'
replace     = require 'gulp-replace'
rename      = require 'gulp-rename'
rev         = require 'gulp-rev'
tap         = require 'gulp-tap'
uglify      = require 'gulp-uglify'
usemin      = require 'gulp-usemin'
highlight   = require('highlight.js').highlightAuto
yaml        = require('js-yaml').safeLoad

pkg         = require './package.json'

# 配置文件
config      = require './config'

# 目录结构
dir =
  tmp:      './.tmp'
  src:      './src'
  pub:      './public'
  asset:    './public/assets'
  postPub:  './public/posts'
  postSrc:  './posts'
  theme:    "./themes/#{config.theme}"

# 文章缓存
posts = []

gulp.task 'new', ->
  now = (new Date).toISOString().replace /(.+)T(.+)\..+/, '$1 $2'
  gulp.src "#{dir.src}/empty.md"
  .pipe replace /\{\{date\}\}/g, now
  .pipe rename "#{now.replace /[: ]/g, '-'}.md"
  .pipe gulp.dest "#{dir.postSrc}/"

gulp.task 'posts', ->
  posts = []
  i = 0
  gulp.src "#{dir.postSrc}/**/*.{md,markdown}"

  # 读取元数据
  .pipe replace /^([\S\s]+?)[\r\n]+?---[\r\n]/m, ($0, $1) ->
    post = yaml $1
    post.date = (post.date || new Date).getTime()
    post.title = post.title || post.date
    posts.push post
    ''

  # 更多分隔位置
  .pipe replace /<!--[ \t]*?more[ \t]*?-->/, '<a id=more></a>'

  # 编译 markdown
  .pipe marked
    highlight: (code) ->
      highlight(code).value

  # 标记图片行
  .pipe replace /<p>(.*?)<img src(.*?)>([\S\s]*?)<\/p>/gm, '<p class=img>$1<img src$2>$3</p>'

  # 站外链接使用新窗口打开
  .pipe replace /<a href="http(.*?)>/g, '<a href="http$1 target=_blank>'

  # 压缩
  .pipe minifyHtml()

  # 输出
  .pipe gulp.dest "#{dir.postPub}"

  # 记录路径
  .pipe tap (file, t) ->
    post = posts[i++]
    post.path = path.relative dir.postPub, file.path
    console.log "[#{post.path}] #{post.title} (#{new Date(post.date)})"

gulp.task 'publish', ['posts'], ->
  fs.mkdir dir.asset, ->
    fs.writeFile "#{dir.asset}/index.json", JSON.stringify
      config: config
      posts: posts

gulp.task 'publish-reload', ['publish'], ->
  gulp.src "#{dir.pub}/index.html"
  .pipe connect.reload()

gulp.task 'publish-watch', ->
  gulp.watch "#{dir.postSrc}/**/*.{md,markdown}", ['publish-reload']

gulp.task 'clean', ->
  gulp.src "#{dir.asset}/*.{js,css}"
  .pipe clean()

gulp.task 'js', ->
  gulp.src "{#{dir.src},#{dir.theme}/scripts}/{,*/}*.coffee"
  .pipe coffee
    bare: true
  .pipe ngAnnotate()
  .pipe gulp.dest "#{dir.tmp}/scripts/"

gulp.task 'template', ->
  gulp.src "#{dir.theme}/views/{,*/}*.html"
  .pipe minifyHtml
    empty: true
    conditionals: true
    quotes: true
  .pipe html2js
    outputModuleName: pkg.name
    base: "#{dir.theme}/views"
    singleModule: true
  .pipe concat 'templates.js'
  .pipe gulp.dest "#{dir.tmp}/scripts/"

gulp.task 'css', ->
  gulp.src "#{dir.theme}/styles/*.less"
  .pipe less
    report: 'min'
    optimization: 1
    relativeUrls: false
    ieCompat: true
    strictImports: true
    strictMath: false
    strictUnits: false
  .pipe apf
    browsers: [
      'last 2 versions'
      '> 1%'
    ]
  .pipe gulp.dest "#{dir.tmp}/styles/"

useminTheme = (useminConfig) ->
  gulp.src "#{dir.theme}/views/*.html"
  .pipe replace /<title([\S\s]*?)>[\S\s]*?<\/title>/, "<title$1>#{config.title}</title>"
  .pipe replace /<meta name="description"[\S\s]*?>/, "<meta name=\"description\" content=\"#{config.description}\">"
  .pipe usemin useminConfig
  .pipe gulp.dest "#{dir.pub}/"

gulp.task 'usemin', ['clean', 'template', 'js', 'css'], ->
  useminTheme
    css: [
      minifyCss()
      rev()
    ]
    js: [
      uglify()
      rev()
    ]
    html: [
      minifyHtml
        empty: true
        conditionals: true
        quotes: true
    ]

gulp.task 'usemin-debug', ['clean', 'template', 'js', 'css'], ->
  useminTheme()

gulp.task 'asset', ->
  gulp.src "#{dir.theme}/assets/*"
  .pipe gulp.dest dir.asset

gulp.task 'theme', ['usemin', 'asset'], ->
  gulp.src dir.tmp, read: false
  .pipe clean()

gulp.task 'theme-reload', ['usemin-debug', 'asset'], ->
  gulp.src "#{dir.pub}/index.html"
  .pipe connect.reload()

gulp.task 'theme-watch', ->
  gulp.watch "{#{dir.src},#{dir.theme}}/**/*.*", ['theme-reload']

gulp.task 'connect', ->
  connect.server
    root: dir.pub
    hostname: '0.0.0.0'
    port: 80
    livereload: true
    middleware: (connect, options) ->
      [(req, res, next) ->
        method = req.method.toUpperCase()
        console.log "#{method} #{req.url}"
        if 'POSTPUTDELETE'.indexOf(method) > -1
          filepath = path.join options.root, req.url
          if fs.existsSync(filepath) && fs.statSync(filepath).isFile()
            res.end fs.readFileSync filepath
        next()
      ]

gulp.task 'server', [
  'publish'
  'connect'
  'publish-watch'
]

gulp.task 'theme-dev', [
  'usemin-debug'
  'asset'
  'connect'
  'theme-watch'
]

gulp.task 'default', [
  'theme'
  'publish'
]